#include <stdio.h>
#include <string.h>

#include "psam_card.h"

inline s32 psam_card_get_key(reader_op *reader, u8 key_flag, u8 key_id)
{
	int ret;
	reader_data send, recv;

	if (!reader) {
		printf("mifare_cpu_get_key pare error!!!\n");
		return RET_ERR;
	}

	send.data 	= reader->send_data;
	recv.data   = reader->deal_in_data.m1.key_data;

	memset(send.data, 0, READER_BUF_SIZ);
	memcpy(send.data, reader->deal_in_data.card_num, 8); 

	if (DEBUG_APP_WALL > __DEBUG_APP_O3__) {
		int i;
		printf("psam_catd_get_key:card num@");
		for (i=0; i<8; i++) {
			printf("%02x", reader->deal_in_data.card_num[i]);
		}
		printf("\n");
	}

	/* PSAM通用DES初始化-(PSAM内部产生子密钥) */
	send.type    = READER_CONTACT_SAM1;
	send.cla	 = 0x80;
	send.cmd.ins = APDU_INIT_FOR_DESCRYPT;
	send.pa1.p1  = key_flag; 
	send.pa2.p2  = key_id;  
	send.len.lc  = 0x08; 
	send.le      = 0x00; 

	ret = reader_communication(reader->fd, &send, &recv);
	if (((recv.sw1 << 8) | recv.sw2) != 0x9000) {
		printf("mifare_card_get_key no.1 failed!!! errno: [%02x%02x]\n", \
			recv.sw1, recv.sw2);
		return ((recv.sw1 << 8) | recv.sw2);
	}

	if (DEBUG_APP_WALL > __DEBUG_APP_O3__) {
		printf("reader: %x %x %x %x %x %x %x %x\n", reader->recv_data[0], \ 
			reader->recv_data[1], reader->recv_data[2], reader->recv_data[3], \
			reader->recv_data[4], reader->recv_data[5], reader->recv_data[6], \
			reader->recv_data[7]);
	}

	/* PSAM DES计算-获得过程密钥 */
	memset(send.data, 0, READER_BUF_SIZ);
	if (READER_CONTACTLESS_CPU == reader->type) { 
		memcpy(send.data, reader->recv_data, 8);
	}
	else {
		strncpy(send.data, CTCC_YJD_KEY_NAME, \
			strlen(CTCC_YJD_KEY_NAME));
	}

	send.type    = READER_CONTACT_SAM1;
	send.cla	 = 0x80;
	send.cmd.ins = APDU_DES_CRYPT;
	send.pa1.p1  = 0x00; 
	send.pa2.p2  = 0x00; 
	send.len.lc  = 0x08; 
	send.le      = 0x00; 

	ret = reader_communication(reader->fd, &send, &recv);
	if (recv.sw1 == 0x61) {
		psam_apdu_get_response(&send, &recv);
		ret = reader_communication(reader->fd, &send, &recv);
	}
	
	if (((recv.sw1 << 8) | recv.sw2) != 0x9000) {
		printf("mifare_card_get_key no.2 failed!!! errno: [%02x%02x]\n", \
			recv.sw1, recv.sw2);
		return ((recv.sw1 << 8) | recv.sw2);
	}

	return RET_OK;
}

static s32 psam_apdu_select_mf(reader_data *send, reader_data *recv)
{
	if (!send->data || !recv->data) {
		printf("psam_apdu_select_mf para error!!!\n");
		return RET_ERR;
	}

	/* 选择MF */
	memset(send->data, 0, READER_BUF_SIZ);
	send->type    = READER_CONTACT_SAM1;
	send->cla     = 0x00;
	send->cmd.ins = APDU_SELECT_FILE;
	send->pa1.p1  = 0x00;
	send->pa2.p2  = 0x00;
	send->len.lc  = 2;
	send->le      = 0;
	send->data[0] = 0x3F;
	send->data[1] = 0x00;
	memset(recv->data, 0, READER_BUF_SIZ);

	return RET_OK;
}


s32 psam_apdu_get_response(reader_data *send, reader_data *recv)
{
	if (!send->data || !recv->data) {
		printf("psam_apdu_get_response para error!!!\n");
		return RET_ERR;
	}

	// 获取结果数据
	memset(send->data, 0, READER_BUF_SIZ);
	send->type	  = READER_CONTACT_SAM1;
	send->cla	  = 0x00;
	send->cmd.ins = APDU_GET_RESPONSE;
	send->pa1.p1  = 0x00;
	send->pa2.p2  = 0x00;
	send->len.lc  = 0;
	send->le      = recv->sw2;
	memset(recv->data, 0, READER_BUF_SIZ);

	return RET_OK;
}


static s32 psam_apdu_read_binary(reader_data *send, reader_data *recv)
{
	if (!send->data || !recv->data) {
		printf("psam_apdu_init_antenna para error!!!\n");
		return RET_ERR;
	}

	// 读②进制文件
	memset(send->data, 0, READER_BUF_SIZ);
	send->type    = READER_CONTACT_SAM1;
	send->cla     = 0x00;
	send->cmd.ins = APDU_READ_BINARY;
	send->pa1.p1  = 0x96;
	send->pa2.p2  = 0x00;
	send->len.lc  = 0;
	send->le      = 6;
	memset(recv->data, 0, READER_BUF_SIZ);

	return RET_OK;
}


s32 psam_apdu_select_dir(reader_data *send)
{
	if (!send->data || !send) {
		printf("psam_apdu_init_antenna para error!!!\n");
		return RET_ERR;
	}

	// 进入应用目录
	send->type    = READER_CONTACT_SAM1;
	send->cla     = 0x00;
	send->cmd.ins = APDU_SELECT_FILE;
	send->pa1.p1  = 0x00;
	send->pa2.p2  = 0x00;
	send->len.lc  = strlen(send->data);
	send->le      = 0;

	return RET_OK;
}

/*
 * 获取终端机编号并进入应用目录
 */
s32 psam_card_init(reader_op* reader)
{
	s32 ret = 0;
	reader_data send, recv;

	if (reader->fd <= 0 || !reader->recv_data \
		|| !reader || !reader->send_data) {
		printf("psam_card_init para error!!!\n");
		return RET_ERR;
	}

	// 选择MF文件
	recv.data = reader->recv_data;
	send.data = reader->send_data;
	psam_apdu_select_mf(&send, &recv);
	ret = reader_communication(reader->fd, &send, &recv);
	if (recv.sw1 == 0x61) {
		psam_apdu_get_response(&send, &recv);
		ret = reader_communication(reader->fd, &send, &recv);
		if (((recv.sw1 << 8) | recv.sw2) != 0x9000) {
			printf("psam select MF [%02x%02x]\n", recv.sw1, recv.sw2);
			return ((recv.sw1 << 8) | recv.sw2);
		}
	}		
	else {
		printf("psam_card_init:psam select MF failed!!! errno:[%02x%02x]\n", \
			recv.sw1, recv.sw2);
		return RET_ERR;
	}

	// 读取PSAM终端号
	psam_apdu_read_binary(&send, &recv);
	ret = reader_communication(reader->fd, &send, &recv);
	if (((recv.sw1 << 8) | recv.sw2) != 0x9000) {
		printf("get terminal num failed!!! errno:[%02x%02x]\n", \
			recv.sw1, recv.sw2);
		return ((recv.sw1 << 8) | recv.sw2);
	}


	memcpy(reader->psam_out_data.terminal, recv.data, recv.len.lc-2);

	// 选择应用文件
	strncpy(send.data, reader->psam_in_data.psam_path, \
		sizeof(reader->psam_in_data.psam_path));
	psam_apdu_select_dir(&send);
	ret = reader_communication(reader->fd, &send, &recv);
	if (recv.sw1 == 0x61) {
		psam_apdu_get_response(&send, &recv);
		ret = reader_communication(reader->fd, &send, &recv);
		if (((recv.sw1 << 8) | recv.sw2) != 0x9000) {
			printf("psam select dir [%02x%02x]\n", recv.sw1, recv.sw2);
			return ((recv.sw1 << 8) | recv.sw2);
		}
	}	
	else {
		printf("psam_card_get_key:psam select dir failed!!! errno:[%02x%02x]\n", \
			recv.sw1, recv.sw2);
		return RET_ERR;
	}

	if (DEBUG_APP_WALL > __DEBUG_APP_O0__)
		printf("DEBUG_info: PSAM select file done\n");


	return RET_OK;
}


s32 psam_card_apdu_comm(reader_data *send, u8 len, s8 *key_data, u8 type, s8 *mac)
{
	s32 i = 0;
	s8 psam_buff[32];
	s8 psam_sesk[32];

	if (!send || !key_data) {
		printf("psam_card_apdu_comm: para error!!!\n");
	}

	switch (send->cmd.ins) {
		case APDU_INIT_SAM_FOR_PURCHASE: // Mac1
			if (MKEY_TYPE == type) {
				goto mkey;
			}
			else if (SKEY_TYPE == type) {
				//C9 08 44 90 6D 3F D3 C3 1C 1D B1 64 5F 3C B2 BF
				psam_buff[0] = 0xc9;
				psam_buff[1] = 0x08;
				psam_buff[2] = 0x44;
				psam_buff[3] = 0x90;
				psam_buff[4] = 0x6d;
				psam_buff[5] = 0x3f;
				psam_buff[6] = 0xd3;
				psam_buff[7] = 0xc3;
				psam_buff[8] = 0x1c;
				psam_buff[9] = 0x1d;
				psam_buff[10] = 0xb1;
				psam_buff[11] = 0x64;
				psam_buff[12] = 0x5f;
				psam_buff[13] = 0x3c;
				psam_buff[14] = 0xb2;
				psam_buff[15] = 0xbf;
			#if 0
				memcpy(&psam_sesk[0], key_data, 8);
				memcpy(&psam_sesk[8], key_data, 8);
			#endif
				goto skey;			
			}
			break;
			
		default:
			return RET_ERR;
	}

// 主密钥
mkey:
	// 推导子密钥过程
	for (i=0; i<8; i++) { // 第①步 将主序列号分成两段 各8个字节
		psam_buff[i] = send->data[20+i];
		psam_buff[i+8] = ~send->data[20+i];
	}

	// 第②步 推导出子密钥
	cel_des3_ecb_encrypt(8, &psam_buff[0], &psam_buff[16], key_data); // 子密钥左半部分
	cel_des3_ecb_encrypt(8, &psam_buff[8], &psam_buff[24], key_data); // 子密钥右半部分
	
skey:	
	// 第③步 由子密钥获得过程密钥
	psam_buff[0] = send->data[0];
	psam_buff[1] = send->data[1];
	psam_buff[2] = send->data[2];
	psam_buff[3] = send->data[3];
	psam_buff[4] = send->data[4];
	psam_buff[5] = send->data[5];
	psam_buff[6] = send->data[6];
	psam_buff[7] = send->data[7];

	cel_des3_ecb_encrypt(8, &psam_buff[0], &psam_sesk[0], &psam_buff[16]); // 由子密钥左半部分加密
	psam_sesk[8] = psam_sesk[0];
	psam_sesk[9] = psam_sesk[1];
	psam_sesk[10] = psam_sesk[2];
	psam_sesk[11] = psam_sesk[3];
	psam_sesk[12] = psam_sesk[4];
	psam_sesk[13] = psam_sesk[5];
	psam_sesk[14] = psam_sesk[6];
	psam_sesk[15] = psam_sesk[7];

	if (DEBUG_APP_WALL > __DEBUG_APP_O3__) {
		int i;
		printf("psam_card_apdu_comm:psam_sesk@");
		for (i=0; i<16; i++) {
			printf("%02x", psam_buff[i]);
		}
		printf("\n");
	}




	// 第④步 计算MAC1
	memcpy(psam_buff, &send[8], len);
	cel_mac(&psam_sesk[0], &psam_buff[0], 18,  &mac[0]); 	// MAC1
	cel_mac(&psam_sesk[0], &psam_buff[0], 4, &mac[4]);   	// MAC1

	return RET_OK;

}

